#ifndef _GSOLVERBBPV3NOWAIT_H_
#define _GSOLVERBBPV3NOWAIT_H_

#include <iostream>

using namespace std ;

#include "gsearchnode.h"
#include "gchrono.h"

#include "gsolverBBPv3.h"

#include "gsupplyLinkProblem.h"
#include "gsupplyLinkSolution.h"
#include "gsupplyLinkSolutionPartial.h"


// Comment this line to have a sequential programm 
//#define GMPI 1


/**
 * PARAMETER TO DISPATCH EFFICIENTLY THE WORK FROM THE MASTER TO THE SLAVES
 */

/**
 * PERIOD OF THE MPI Communication TEST in seconds : 
 * If the value is low, the MPI communication tests will be more frequent
 * If the value is high, the MPI communication tests will be less frequent
 */
// Comment the following line to avoid dynamic change of the MPI communication test period.
#define GADJUST_PERIOD_MPI_TEST
#define DEFAULT_PERIOD_MPI_TEST_SLAVE   0
#define DEFAULT_PERIOD_MPI_TEST_MASTER  0

/**
 * The maximum period of the MPI communication test in seconds
 */
#define MAX_PERIOD_MPI_TEST            60

/**
 * RATIO between the average processing time for a slave node and 
 * the dynamic period of the MPI communication test.
 * 
 * Principle : the frequency of the MPI communication test should be proportionnal
 *             to the mean processing time of the slave. 
 *   - if the slave work is short, the MPI comm test should be more frequent
 *   - if the slave work is long, the MPI comm test should be less frequent
 */
#define RATIO_MEANTIME_PERIOD_MPI_TEST 5.0

/**
 * The minimum number of processing times for a slave or master, to modify the MPI comm period
 */ 
#define MIN_NBR_STAT                   5

/**
 * Dynamic dispatching of the work from the master to the slaves
 */
#define MIN_LEVEL_FOR_DISPATCHING 10

// Attention, il faut retrancher MAX_LEVEL_FOR_DISPATCHING du nombre de jobs pour
// obtenir le niveau de profondeur max associé au dispatching vers les esclaves
#define MAX_LEVEL_FOR_DISPATCHING 30


#define WORK_DISPATCHED            1
#define WORK_NOT_DISPATCHED        2



/**
 * A BBP solver : starts with jobs with last due dates
 *
 * Dans cette version 3 de la BBP, on demarre avec les jobs reordonnes dans le sens des dates dues croissantes. Mais
 * contrairement a l'exploration brutale de la version 2, cette fois on ne considere pas n'importe quel numero de batch.
 * Pour chaque job, on choisit de le rajouter soit dans un batch deja existant dont la capacite residuel est suffisante
 * pour stocker le nouveau job, soit dans un nouveau batch.
 *
 * Le nouveau batch est ordonnance avant les autres batchs deja crees.
 *
 * ATTENTION : Pour que cette solution soit optimale, sachant que l'on
 * part d'un probleme pour lequel les jobs sont classes par date due croissante, il est egalement necessaire que le cout de stockage
 * de tous les jobs soient identiques. Dans le cas contraire, la solution ainsi construite n'est plus certaine d'etre optimale.
 */
class GSolverBBPv3NoWait : public GSolverBBPv3 {
 protected:
  /**
   * Interval of the search tree to dispatch the work to the slaves
   * If the task are too small, the time to communicate will be very high
   * if the task are too important, some nodes could starve and will have nothing to do.
   * 
   * As the search is done from the last job n back to the first one, these values should
   * be rather close than 100% than 0% in order to to schedule few big tasks rather than 
   * a lot of small tasks. 
   *
   * depthLevel 0 = root of the searchtree (job=problem.getNP()-1)
   * depthLevel max for job=0
   */
  int depthLevelForDispatching ;

  /**
   * Period of the MPI communication test inside the tree search procedure
   * If the period is low, there will be a lot of MPI_Test call which could
   * increase significantly the overall processing time of the procedure.
   * On the opposite, if the period of communication test is large, there will 
   * be more time for computation, however the propagation of a better 
   * evaluation could be slowed down, as well as the propagation of the 
   * information that a slave has finished its work.
   */
  galarm alarmMPITestSlave, alarmMPITestMaster ;

  int onlyNewBatchFirst ;
  int lowerBoundLevel ;

  GLowerBound* lowerBound ;
  
  long nbrCut, nbrTreeNodes ;

 public:
  GSolverBBPv3NoWait(GSupplyLinkProblem& pb, int node_, int p_=0) ;
  virtual ~GSolverBBPv3NoWait() ;

  void setLowerBoundLevel(int l) ;

  void setDepthLevelForDispatching (int d) ;

  void setPeriodMPITestSlave (int period) ;
  void setPeriodMPITestMaster (int period) ;

  void setPeriodMPITestParameter (int periods, int periodm) ;

  void setOnlyNewBatchFirst(int f) { onlyNewBatchFirst = f ; }

  /**
   * The main structure of the method "DepthFirstSearch" is common to the master and the slaves.
   * The difference resides in the following three steps :
   * - check the MPI communication is different
   * - the work to do when a better solution is found
   * - the work to do before exploring further the search tree
   */ 
  virtual void depthFirstSearch(const searchnode&) ;

  // check the MPI communication is different
  virtual void testForMPIComm() = 0 ;

  // the work to do when a better solution is found
  virtual void sendMPICommForBestSolution(double) = 0 ;

  // the work to do before exploring further the search tree
  virtual int dispatchWork() = 0 ;
  virtual int pushWork(searchnode&) = 0 ;

  virtual void solveInit() ;
  virtual void solveEnd() ;


} ;

#endif
